/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jigdo.io;

import jigdo.JigdoException;
import jigdo.data.template.section.*;
import jigdo.data.template.section.DESCEntries.*;
import jigdo.data.template.*;
import jigdo.utils.*;
import java.io.*;
import java.util.logging.Logger;
import static jigdo.io.JigdoFileReader.logger;

/**
 * Utility class to read a jigdo template from the disk.
 *
 * @author John R Sohn
 * @see jigdo.data.template.JigdoTemplate
 */
public class TemplateFileReader {
    
    public static void setParentLogger(Logger parent) {
        logger.setParent(parent);
        logger.setLevel(null);
    }
    static Logger logger = Logger.getLogger(JigdoFileReader.class.getName());

    /**
     * Private method which moves to the next section marker in the file and
     * parses it.
     *
     * @param file the current file stream
     * @return The next file marker indicator
     * @throws java.io.IOException
     */
    private static String NextMarker(java.io.InputStream file) throws java.io.IOException {
        int b = file.read();
        
        String datak = "DATA";
        String desck = "DESC";
        String bzip = "BZIP";
        String curr = "";
        
        while (b != -1) {
            curr += (char) b;
            
            if (!(datak.indexOf(curr) == 0 || desck.indexOf(curr) == 0 || bzip.indexOf(curr) == 0)) {
                curr = "";
            } else if (curr.equals(bzip) || curr.equals(desck) || curr.equals(datak)) {
                return curr;
            }
            
            b = file.read();
        }
        
        throw new java.io.IOException("End of file reached with no keyword found.");
    }

    /**
     * Reads a character stream from the provided file input stream
     *
     * @param file
     * @return The string read.
     * @throws java.io.IOException
     */    
    private static String NextLine(java.io.InputStream file) throws java.io.IOException {
        
        String currline = "";
        String delim = "";
        
        String delimconst = "\r\n";
        
        int b = file.read();
        
        while (b != -1) {
            delim += (char) b;
            
            if (delimconst.indexOf(delim) != 0) {
                delim = "";
                currline += (char) b;
            } else if (delim.equals(delimconst)) {
                return currline;
            }
            
            b = file.read();
        }
        
        throw new IOException("End of file reached before next line found.");
    }

    /**
     * Reads and parses the jigdo .template file and returns an object tree.
     *
     * @param filename
     * @return The parsed jigdo template
     * @throws java.io.IOException
     * @throws JigdoException
     */
    public static JigdoTemplate ReadEntry(byte[] src) throws java.io.IOException, JigdoException {
        
        java.io.ByteArrayInputStream bi;

        //  java.io.FileInputStream file = new java.io.FileInputStream(filename);

        JigdoTemplate jtemp = new JigdoTemplate();

        //java.nio.channels.FileChannel chan = file.getChannel();
        
        jigdo.utils.BetterByteStream file = new jigdo.utils.BetterByteStream(src);
        
        jtemp.Header = NextLine(file) + "\r\n" + NextLine(file) + "\r\n" + NextLine(file);
        
        
        while (file.getPosition() < file.getLength() - 1) {
            
            String markerName = NextMarker(file);

            // determine the file type, get the proper object
            TemplateSection currSection = TemplateSection.GetSpecificType(jtemp, markerName);

            // use generic file structure rules to retrieve object
            currSection.ReadSelf(file);

            // add section and update counters
            jtemp.AddSection(currSection);
        }
        
        file.close();
        
        int sectionoffset = 0;
        
        
        DESCDataIterator descIt = jtemp.Description.GetIterator();
        TemplateDataIterator tempDataIt = jtemp.GetIterator();
        
        
        if (tempDataIt.hasNext()) {
            int bytesRemaining = 0;
            int currSRCIndex = 0;
            
            TemplateDATASection data = tempDataIt.next();
            
            logger.fine(data.toString());
            
            // iterate through the rawdata description entries
            while (descIt.hasNext()) {
                
                
                TemplateDESCRawDataEntry entry = descIt.next();
                
                bytesRemaining = entry.SkipLength;
                
                logger.fine("Bytes Remaining: "+Integer.toString(bytesRemaining));
                // iterate through enough template data sections to cover all
                // needed data in the current entry
                while (bytesRemaining > 0) {
                    
                    logger.fine("Bytes Remaining: "+Integer.toString(bytesRemaining));
                    
                    DATARange newd = new DATARange();
                    
                    newd.Source = data;
                    newd.StartIndex = currSRCIndex;
                    newd.EndIndex = currSRCIndex+bytesRemaining -1;
                   
                    if (newd.EndIndex > data.UncompressedLength-1)
                    {
                        newd.EndIndex = data.UncompressedLength-1;
                        bytesRemaining -= newd.getLength();
                        data = tempDataIt.next();
                        currSRCIndex=0;
                    }
                    else
                    {
                        
                        
                        bytesRemaining-= newd.getLength();
                        
                        currSRCIndex=newd.EndIndex+1;
                        
                        
                        if (currSRCIndex == data.UncompressedLength)
                        {
                            if (tempDataIt.hasNext())
                            {
                                data = tempDataIt.next();
                                currSRCIndex=0;
                            }
                        }
                    }
                    
                    entry.SourceRanges.add(newd);
                   logger.fine(newd.toString());
                  
                }
            }
        }
        
        return jtemp;
    }
}
